<?php
require_once 'Request.php';
require_once 'Router/Exception.php';
class Simpple_Controller_Router {
	private $rules = array();
	private $compiledRules = array();
	private static $tmpKeys;
	private static $tmpMaps = array();
	private $modules;
	
	/**
	 * 设置模块
	 *
	 * @param array $modules
	 */
	public function setModules($modules = null) {
		$this->modules = $modules;
	}
	
	/**
	 * 从url获取访问参数
	 *
	 * @return string
	 */
	public function getParamsFromUrl() {
		$url = $_SERVER['REQUEST_URI'];
		if (($pos = strpos($url, '?')) !== false) {
			$url = substr($url, 0, $pos);
		}
		$url = substr($url, 1);
		
		$moduleName = '';
		if ($url && is_array($this->modules)) {
			$pos = strpos($url, '/');
			if ($pos === false) {
				$moduleName = $url;
				$tmpUrl = '';
			} else {
				$moduleName = substr($url, 0, $pos);
				$tmpUrl = substr($url, $pos + 1);
			}
			$index = array_search($moduleName, $this->modules);
			if ($index >= 0) {
				$url = $tmpUrl;
			} else {
				$moduleName = '';
			}
		}
		$controller = $action = '';
		$params = $this->getParams($url);
		if ($params === false) {
			$params = array();
			if (strpos($url, '/') !== false) {
				list($controller, $action) = explode('/', $url);
			} else {
				$controller = $url;
			}
			if (!$controller) {
				$controller = Simpple_Controller_Request::DEFAULT_CONTROLLER;
			}
			if (!$action) {
				$action = Simpple_Controller_Request::DEFAULT_ACTION;
			}
			
			$params[Simpple_Controller_Request::CONTROLLER_KEY] = $controller;
			$params[Simpple_Controller_Request::ACTION_KEY] = $action;
		}
		if ($moduleName) {
			$params['module'] = $moduleName;
		}
		return $params;
	}
	
	/**
	 * 根据规则处理url
	 *
	 * @param string $url
	 */
	private function getParams($url) {
		$params = array();
		foreach($this->rules as $rule) {
			if ($rule['compiled'] == $rule['rule']) {
				if ($url == $rule['rule']) {
					$params = $rule['router'];
					return $params;
				}
				continue;
			}
			$reg = '{^'.$rule['compiled'].'$}';
			
			if (preg_match($reg, $url, $matches)) {
				array_shift($matches);
				foreach($rule['maps'] as $key) {
					$params[$key] = array_shift($matches);
				}
				
				if (isset($rule['router'])) {
					foreach($rule['router'] as $key=>$value) {
						$params[$key] = $value;
					}
				}
				
				return $params;
			}
		}
		return false;
	}
	
	/**
	 * 增加规则
	 *
	 * @param array $rule
	 */
	public function addRule($rule) {
		$compiledRule = $this->compileRule($rule);
		$this->rules[] = $compiledRule;
	}
	
	/**
	 * 回调替换
	 *
	 * @param array $matches
	 */
	public static function pregCallback($matches) {
		$key = $matches[1];
		$key = substr($key, 1, -1);
		self::$tmpMaps[] = $key;
		if (!self::$tmpKeys || !isset(self::$tmpKeys[$key]) ){
			return '([^/]+)';
		}
		return '('.self::$tmpKeys[$key].')'; 
	}
	
	/**
	 * 编译规则
	 * 
	 * @param array $rule 
	 * @example array(
	 * 'rule'=>'post/{postId}',
	 * 'router'=>array(
	 * 	'controller'=>'post',
	 * 	'action'=>'index'
	 * ),
	 * 'keys' => array(
	 * 	'postId' => '\d+'
	 * 	),
	 * )
	 */
	private function compileRule($rule) {
		if (!isset($rule['rule'])) {
			throw new Simpple_Controller_Router_Exception('the rule is not defined');
		}
//		if (!isset($rule['router'])) {
//			throw new Simpple_Controller_Router_Exception('the router is not defined');
//		}
		if (strpos($rule['rule'], '{') === false) {
			$rule['compiled'] = $rule['rule'];
			return $rule;
		}
		
		self::$tmpKeys = key_exists('keys', $rule) ? $rule['keys'] : null;
		self::$tmpMaps = array();
		$str = preg_replace_callback("/({[^\/}]+})/", 'self::pregCallback', $rule['rule']);
		$rule['compiled'] = $str;
		$rule['maps'] = self::$tmpMaps;
		return $rule;
	}
}